package GUI_Element;

import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import Kernel.Arc;
import Kernel.Arc_P2T;
import Kernel.Arc_T2P;

public class ShapeArc extends Element {

	/* If it's a P2T arc, then arcP2T is valid. T2P likewise. */
	private Arc_P2T arcP2T;
	private Arc_T2P arcT2P;
	final public static int TYPEP2T = 1;
	final public static int TYPET2P = 2;
	
	
	/* The point-to end coordinate and the arrow scale */
	private float x2;
	private float y2;
	private float ForeMargin;
	private float BackMargin;
	final private static float ArrowLength = 5;
	
	/* The place and transition the arc points to */
	private ShapePlace sp;
	private ShapeTransition st;
	
	/* GUI elements */
	private Line2D.Float line=null;
	private Line2D.Float arrowline1=null;
	private Line2D.Float arrowline2=null;

	public ShapeArc(int type, ShapePlace sp, ShapeTransition st) {
		if (type == TYPEP2T || type == ARCP2T) {
			this.type = ARCP2T;
			sp.AddPost(this);
			st.AddPre(this);
			arcP2T = new Arc_P2T(sp.GetActual(), st.GetActual());
			ForeMargin = (float)(ShapeTransition.SideLength * 0.75);
			BackMargin = (float)(ShapePlace.Radius);
		}
		else if (type == TYPET2P || type == ARCT2P) {
			this.type = ARCT2P;
			st.AddPost(this);
			sp.AddPre(this);
			arcT2P = new Arc_T2P(st.GetActual(), sp.GetActual());
			ForeMargin = (float)(ShapePlace.Radius);
			BackMargin = (float)(ShapeTransition.SideLength * 0.75);
		}
		else
			throw new RuntimeException();
		this.sp = sp;
		this.st = st;

		shape = line = new Line2D.Float();
		arrowline1 = new Line2D.Float();
		arrowline2 = new Line2D.Float();
	}
	
	public ShapeArc(ObjectInputStream ois, 
			ShapePlace[] placeSet, ShapeTransition[] transitionSet) throws IOException {
		type = ois.readInt();
		sp = placeSet[ois.readInt()-1];
		st = transitionSet[ois.readInt()-1];
//		System.out.println(sp.GetActual().PlaceIndex + " " + st.GetActual().TransitionIndex);
		if (type == TYPEP2T || type == ARCP2T) {
			sp.AddPost(this);
			st.AddPre(this);
			arcP2T = new Arc_P2T(sp.GetActual(), st.GetActual());
			arcP2T.Load(ois);
			ForeMargin = (float)(ShapeTransition.SideLength * 0.75);
			BackMargin = (float)(ShapePlace.Radius);
		} else if (type == TYPET2P || type == ARCT2P) {
			st.AddPost(this);
			sp.AddPre(this);
			arcT2P = new Arc_T2P(st.GetActual(), sp.GetActual());
			arcT2P.Load(ois);
			ForeMargin = (float)(ShapePlace.Radius);
			BackMargin = (float)(ShapeTransition.SideLength * 0.75);
		} else
			throw new RuntimeException();
		
		shape = line = new Line2D.Float();
		arrowline1 = new Line2D.Float();
		arrowline2 = new Line2D.Float();	
	}

	public Element Clone() {
		return null;
	}

	public void draw(Graphics2D g) {
		if (isSelected)
			g.setColor(Element.SelectedColor);
		else
			g.setColor(Element.NormalColor);
		if (toBeDeleted)
			g.setColor(Element.DeleteColor);
		
		long weight;
		if (type == Element.ARCP2T) {
			x1 = sp.getX1();
			y1 = sp.getY1();
			x2 = st.getX1();
			y2 = st.getY1();
			weight = arcP2T.GetWeight();
		}
		else if (type == Element.ARCT2P) {
			x1 = st.getX1();
			y1 = st.getY1();
			x2 = sp.getX1();
			y2 = sp.getY1();
			weight = arcT2P.GetWeight();
		}
		else 
			throw new RuntimeException();
		
		float 
			length = (float)Math.sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)),
			X1 = x1 - (x1-x2)*BackMargin/length,
			Y1 = y1 - (y1-y2)*BackMargin/length,
			X2 = x2 - (x2-x1)*ForeMargin/length,
			Y2 = y2 - (y2-y1)*ForeMargin/length,
			MY = Y2 - (Y2-Y1)/length*ArrowLength,
			MX = X2 - (X2-X1)/length*ArrowLength,
			X3 = MY-Y2+MX,
			Y3 = X2-MX+MY,
			X4 = Y2-MY+MX,
			Y4 = MX-X2+MY;
		
		line.setLine(X1, Y1, X2, Y2);
		arrowline1.setLine(X2, Y2, X3, Y3);
		arrowline2.setLine(X2, Y2, X4, Y4);
		g.draw(line);
		g.draw(arrowline1);
		g.draw(arrowline2);
		
		if (weight > 1) 
			g.drawString(""+weight, (x1+x2)/2-10, (y1+y2)/2-8);
	}

	public Arc GetActual() {
		if ( type == Element.ARCP2T )
			return arcP2T;
		else if ( type == Element.ARCT2P )
			return arcT2P;
		else
			throw new RuntimeException();
	}
	public ShapePlace GetPlace() {
		return sp;
	}
	public ShapeTransition GetTransition() {
		return st;
	}
	public boolean OnLine(float x, float y) {
		float x1 = sp.getX1(), y1 = sp.getY1(),
			x2 = st.getX1(), y2 = st.getY1();
		if ( x > Math.max(x1, x2) || x < Math.min(x1, x2)) return false;
		if ( y > Math.max(y1, y2) || y < Math.min(y1, y2)) return false;
		return (new Float(Math.atan2(y2-y1, x2-x1) - Math.atan2(y-y1, x-x1))).compareTo((float)0.1)<0;
//		return  ((Float)(Math.abs((y2-y1)/(x2-x1) - (y-y1)/(x-x1)))).compareTo((float)0.3)<0;
	}
	
	public void Store(ObjectOutputStream oos) throws IOException{
		oos.writeInt(type);
		oos.writeInt(sp.GetActual().PlaceIndex);
		oos.writeInt(st.GetActual().TransitionIndex);
		if ( type == TYPEP2T || type == ARCP2T )
			arcP2T.Store(oos);
		else if ( type == TYPET2P || type == ARCT2P)
			arcT2P.Store(oos);
		else
			throw new RuntimeException("Wrong Arc Type");
	}
}
